package handler

import (
	"io"
	"react-router/model"
	"time"

	"github.com/gofiber/fiber/v2"
)

// RouteGroup 路由分组接口
type RouteGroup interface {
	SetupRoutes(group fiber.Router)
}

type UploadConfig struct {
	MaxFileSize  int64
	AllowedTypes map[string]bool
}

// UploadRoutes 上传相关路由
type UploadRoutes struct {
	handler UploadHandler
	repo    FileRepository
	config  UploadConfig
}

func NewUploadRoutes(handler UploadHandler, repo FileRepository, config UploadConfig) *UploadRoutes {
	return &UploadRoutes{
		handler: handler,
		repo:    repo,
		config:  config,
	}
}

func (r *UploadRoutes) SetupRoutes(group fiber.Router) {
	uploadGroup := group.Group("/upload")

	// 文件上传
	uploadGroup.Post("/", r.handleFileUpload)

	// 获取文件
	uploadGroup.Get("/:id", r.handleGetFile)

	// 删除文件
	uploadGroup.Delete("/:id", r.handleDeleteFile)
}

func (r *UploadRoutes) handleFileUpload(ctx *fiber.Ctx) error {
	file, err := ctx.FormFile("file")
	if err != nil {
		return NewErrorResponse(ctx, model.ERROR_FILE_UPLOAD)
	}

	// 验证文件大小
	if file.Size > r.config.MaxFileSize {
		return NewErrorResponse(ctx, model.ERROR_FILE_TOO_LARGE)
	}

	// 验证文件类型
	contentType := file.Header.Get("Content-Type")
	if !r.config.AllowedTypes[contentType] {
		return NewErrorResponse(ctx, model.ERROR_UNSUPPORTED_TYPE)
	}

	// 计算文件hash
	hash, err := calculateFileHash(file)
	if err != nil {
		return NewErrorResponse(ctx, model.ERROR_FILE_UPLOAD)
	}

	// 检查文件是否已存在
	existingFile, err := r.repo.FindByHash(hash)
	if err != nil {
		return NewErrorResponse(ctx, model.ERROR_INTERNAL)
	}
	if existingFile != nil {
		return NewSuccessResponse(ctx, existingFile)
	}

	// 读取文件内容
	src, err := file.Open()
	if err != nil {
		return NewErrorResponse(ctx, model.ERROR_FILE_UPLOAD)
	}
	defer src.Close()

	fileBytes, err := io.ReadAll(src)
	if err != nil {
		return NewErrorResponse(ctx, model.ERROR_FILE_UPLOAD)
	}

	// 创建文件记录
	fileModel := &model.File{
		FileName:    file.Filename,
		FileSize:    file.Size,
		ContentType: contentType,
		Data:        fileBytes,
		Hash:        hash,
		Status:      0,
		UploadTime:  time.Now().Unix(),
	}

	if err := r.repo.Create(fileModel); err != nil {
		return NewErrorResponse(ctx, model.ERROR_FILE_UPLOAD)
	}

	return NewSuccessResponse(ctx, fileModel)
}

func (r *UploadRoutes) handleGetFile(ctx *fiber.Ctx) error {
	id, err := ctx.ParamsInt("id")
	if err != nil {
		return NewErrorResponse(ctx, model.ERROR_INVALID_REQUEST)
	}

	if id <= 0 {
		return NewErrorResponse(ctx, model.ERROR_INVALID_REQUEST)
	}

	file, err := r.repo.FindByID(uint(id))
	if err != nil {
		return NewErrorResponse(ctx, model.ERROR_NOT_FOUND)
	}

	if file == nil {
		return NewErrorResponse(ctx, model.ERROR_NOT_FOUND)
	}

	return NewSuccessResponse(ctx, file)
}

func (r *UploadRoutes) handleDeleteFile(ctx *fiber.Ctx) error {
	id := ctx.Params("id")
	file, err := r.repo.FindByHash(id)
	if err != nil || file == nil {
		return NewErrorResponse(ctx, model.ERROR_NOT_FOUND)
	}

	if err := r.repo.Delete(file.ID); err != nil {
		return NewErrorResponse(ctx, model.ERROR_FILE_DELETE)
	}

	return NewSuccessResponse(ctx, nil)
}
